#pragma once

#include <math.h>

/*!
 *	@brief		Simple 2D vector class.
 */
class Vector2 {
public:
	/*!
	 *	@brief		Constructor.
	 *
	 *	@param		x		The x-value of the vector.
	 *	@param		y		The y-value of the vector.
	 */
	Vector2( float x=0.f, float y=0.f ): _x(x), _y(y) {}

	/*!
	 *	@brief		Vector2 difference.
	 *
	 *	@param		v		The vector to subtract.
	 *	@returns	A vector containing the element-wise difference
	 *				of this vector and v.
	 */
	Vector2 operator-( const Vector2 & v ) const {
		return Vector2( _x - v._x, _y - v._y );
	}

	/*!
	 *	@brief		Vector2 addition.
	 *
	 *	@param		v		The vector to add.
	 *	@returns	A vector containing the element-wise difference
	 *				of this vector and v.
	 */
	Vector2 operator+( const Vector2 & v ) const {
		return Vector2( _x + v._x, _y + v._y );
	}

	/*!
	 *	@brief		Scalar multiplication.
	 *
	 *	@param		s		The scale factor.
	 *	@returns	A vector with each element multiplied by s.
	 */
	Vector2	operator*( float s ) const {
		return Vector2( _x * s, _y * s );
	}

	/*!
	 *	@brief		Short-hand for dot product.
	 *
	 *	@param		v		The vector with which the inner product is computed.
	 *	@returns	The inner product (sum of element-wise multiplication)
	 *				of this vector and v.
	 */
	float operator*( const Vector2 & v ) const {
		return _x * v._x + _y * v._y;
	}

	Vector2 operator-() const {
		return Vector2(-_x, -_y);
	}

	/*!
	 *	@brief		Returns a normalized version of this vector
	 *				(same direction, unit length).
	 *
	 *	If the length of the vector < EPS, then the vector
	 *	<1, 0> is returned.
	 *
	 *	@returns	The normalized vector.
	 */
	Vector2 norm() const {
		float mag = magnitude();
		if ( mag > 0.00001f ) {
			return Vector2( _x / mag, _y / mag );
		} else {
			return Vector2( 1.f, 0.f );
		}
	}

	/*!
	 *	@brief		Returns the magnitude of the vector.
	 *
	 *	@returns	The vector magnitude.
	 */
	inline float magnitude() const { return sqrt( _x * _x + _y * _y ); }

	/*!
	 *	@brief		The x-coordinate of the vector.
	 */
	float	_x;


	/*!
	 *	@brief		The y-coordinate of the vector.
	 */
	float	_y;
};

inline Vector2 operator*( float s, const Vector2 & v ) {
	return Vector2( s * v._x, s * v._y );
}

/*!
 *	@brief		Compute the "determinant" of two vectors.
 *
 *	It is the determininat of a 2x2 matrix whose columsn are
 *	made up of v1 an v2.
 *
 *	@param		v1		The first column.
 *	@param		v2		The second column.
 *	@returns	The determinant of the 2x2 matrix.
 */
inline float det( const Vector2 & v1, const Vector2 & v2 ) { 
	return v1._x * v2._y - v1._y * v2._x;
}

/*!
 *	@brief		A line segment.
 */
class Segment {
public:
	/*!
	 *	@brief		Constructor.
	 *
	 *	@param		p0		One end point.
	 *	@param		p1		The other end point.
	 */
	Segment( const Vector2 & p0, const Vector2 & p1 ): _p0(p0), _p1(p1) {}

	/*!
	 *	@brief		Provides the direction from p0 to p1.
	 *
	 *	@returns	A unit-length vector of the direction of the segment form
	 *				p0 to p1.
	 */
	inline Vector2 direction() const { return ( _p1 - _p0 ).norm(); }

	/*!
	 *	@brief		Provides the length fo the segment.
	 *
	 *	@returns	The segment length.
	 */
	inline float length() const { return ( _p1 - _p0 ).magnitude(); }

	/*!
	 *	@brief		Reverses the end point order
	 */
	void flip() {
		Vector2 tmp = _p0;
		_p0 = _p1;
		_p1 = tmp;
	}

	/*!
	 *	@brief		The first end point.
	 */
	Vector2	_p0;

	/*!
	 *	@brief		The first end point.
	 */
	Vector2	_p1;
};

/*!
 *	@brief		Compute the smallest distance between two line segments.
 *
 *	@param		seg1		The first segment.
 *	@param		seg2		The second segmend.
 *	@returns	The distance between the closest features on the two segments.
 */
float minDistance( const Segment & seg1, const Segment & seg2 );

float minDistance( const Segment & seg, const Vector2& v );